#include "evaluate.h"
#include <chrono>

Result evaluate(Cellar& learn,std::vector<Wine*> & test, Result& r){

    std::vector<int> correct(7,0);
    std::vector<int> total(7,0);
    std::vector<int> real(7,0);
    std::vector<int> total_types(2,0);
    std::vector<int> correct_types(2,0);
    std::vector<int> total_pred_types(2,0);
    std::vector<std::vector<Wine*> > wines_for_ques(7);
    std::pair<int,bool> result;
    int ty;
    for(auto i = test.begin(); i != test.end(); i++){
        learn.find(*(*i));
        result = learn.predictClass();
        total_pred_types[result.second ? 0 : 1]++;
        (*i)->predictedType = result.second;
        ty = result.first;
        total[ty - 1]++;
        total_types[(*i)->score.second ? 0 : 1]++; //collects all true values of types
        wines_for_ques[ty - 1].push_back(*i);
        if((*i)->score.first - ty == 0)
            correct[(*i)->score.first - 1]++;
        if((*i)->score.second == result.second)
            correct_types[(*i)->score.second ? 0 : 1]++;
        real[(*i)->score.first - 1]++;
        }
    r.correct_pre = correct;
    r.real_results = real;
    r.total_pre = total;
    r.pre_wines = wines_for_ques;
    r.total_types = total_types;
    r.correct_types = correct_types;
    r.total_pred_types = total_pred_types;
    return r;
}


Result weightLoop(std::vector<double>& weights, int i, Cellar& training,  std::vector<Wine*>& testing, double factor, Result best){
    Result temp = best;
    while(best <= temp){
        weights[i] = weights[i]*factor;
        if(weights[i] < 0.05)
            return best;
        training.setWeightsForWines(weights);
        best = temp;
        temp = evaluate(training,testing, temp);
        }
    weights[i] = weights[i]/factor;
    training.setWeightsForWines(weights);
    return best;
}

Result findLocalMax(std::vector<double>& weights, Cellar& training,  std::vector<Wine*>& testing, Result best){
    Result temp_h;
    Result temp_l;
    int counter = 0;
    std::vector<double> w_copy;
    training.setWeightsForWines(weights);
    best = evaluate(training,testing, best);
    size_t iter = 0;
    while(counter < 12){
        if(iter == weights.size())
            iter = 0;
        w_copy = weights;
        temp_h = weightLoop(w_copy, iter, training, testing, 1.02, best);
        temp_l = weightLoop(weights, iter, training, testing, 0.98, best);
        if(best == temp_l && best == temp_h)
            counter++;
        else
            counter = 0;

        if(temp_l.correct_ones() < temp_h.correct_ones()){
            weights = w_copy;
            best = temp_h;
            training.setWeightsForWines(weights);
        }
        else{
            best = temp_l;
        }
        iter++;
    }
    return best;

}

